/*
 * File:   Query.h
 * Author: karthik
 *A class to provide interface to run b+tree and Pyramid functions in order to support point, range, and KNN type of queries.
 * Created on November 14, 2011, 4:26 PM
 */

#ifndef _QUERY_H
#define	_QUERY_H
#include <list>
#include <stdlib.h>
#include <stdio.h>
#include <iostream>
#include <vector>
#include "Pyramid.h"
#include "ApproximateMedian.h"
using namespace std;
class Query{

public:
    //Dimension of data
    int D;
    //Pyramid class variable used in accessing the functions of it.
    Pyramid p;
    //A structure to store data and query points
    ApproximateMedian am;

    class point{
    public:
    	int id;
    	vector<double> values;
        
    	point(){}

    	point(int pintID, vector<double> in)
    	{
    		unsigned int i;
    		id = pintID;

    		for(i=0;i<in.size();i++)
    		{
    			values.push_back(in[i]);
    		}

    	}

    	void print()
    	{
    		cout << "ID: " << id << " Values: ";
    		for(unsigned int i=0;i<values.size();i++)
    		{
    			cout << values[i] << " ";
    		}
    	}
    };

    //Constructor
    Query(int d);

    //A structure to store KNN, of a given query point q
    class pointk{
    public:
        //ID Attribute from input file for each record
        int id;
        //This variable stores the data points dimensional values
        double values[];
        //Distance from query point q to this point
        double distance;
        pointk(){

        }
        ~pointk(){};
        //Constructor
        pointk(int i, double v[], int dis){
            id = i;
            for(unsigned int i=0; i< sizeof(this->values)/sizeof(double);i++)
            {
                this->values[i] = v[i];
            }
            distance = dis;

        }
        //Copy constructor
        pointk(const pointk &copyin){
            this->id = copyin.id;
            for(unsigned int i=0; i< sizeof(this->values)/sizeof(double);i++)
            {
                this->values[i] = copyin.values[i];
            }

            this->distance = copyin.distance;
        }
        //Overloaded = operator
        pointk& operator=(const pointk &rhs){
            this->id = rhs.id;
             for(unsigned int i=0; i< sizeof(this->values)/sizeof(double);i++)
            {
                this->values[i] = rhs.values[i];
            }
            this->distance = rhs.distance;
            return *this;
        }
        //Overloaded == operator
        int operator==(const pointk &rhs) const{
            if(this->id != rhs.id) return 0;
            for(unsigned int i=0; i< sizeof(this->values)/sizeof(double);i++)
            {
                if(this->values[i] != rhs.values[i]) return 0;
            }
            if(this->distance != rhs.distance) return 0;
            return 1;
        }
        //Overloaded < operator. Note: This operator is modified to support descending sort. Hence it returns 1, when left hand side is greater than rhs
        int operator<(const pointk &rhs) const{
            if(this->distance > rhs.distance) return 1;
            return 0;
        }


    };

    //A variable to store KNN in a list
    list<pointk> A;

    //Calculate and return euclidean distance between two points
    double euclideandistance(point a, point b);

    //Find and return KNN for a given query and k
    list<pointk> pyramidKNN(point q, int k);

    //Perform a point search for a given point
    bool pyramidpointsearch(point a);

    //Performs a range search on the qiven query and returns the ponts found. Functiona input parameter qr, is a [D][2]- dimensional array. For each dimension it has lower and higher range values.
    point * pyramidrangesearch(double qr[][2]);
    
    void hbam(int tr, int d, double **val){};

    //A function to test list for pointk structure; Note this is solely for testing purpose
    void testlist()
{
       list<Query::pointk> A;
       Query::pointk p1;
       p1.id=1;
       p1.distance = 0.5;
       Query::pointk p2;
       p2.id=2;
       p2.distance = 0.6;
       Query::pointk p3;
       p3.id=3;
       p3.distance = 0.2;

       A.push_back(p1);
       A.push_back(p2);
       A.push_back(p3);

       A.sort();

       list<pointk>::iterator i;

       for(i=A.begin(); i != A.end(); ++i){
           cout << i->id << " " << i->distance << "\n";
       }
}










};



#endif	/* _QUERY_H */

